#ifndef _EXT_BLOCK_LOG_H_
#define _EXT_BLOCK_LOG_H_

#include <stdint.h>
#include "rtctime.h"
#include "log_buff_fix.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define FLASH_BLOCK_ERR_NONE 0
#define FLASH_BLOCK_ERR_PAGE_SIZE 1	 
#define FLASH_BLOCK_ERR_BLOCK_SIZE 2 
#define FLASH_BLOCK_ERR_BLOCK_NUMS 3
#define FLASH_BLOCK_ERR_SIZE 4		  
#define FLASH_BLOCK_ERR_PAG_PER_BLK 5 
#define FLASH_BLOCK_ERR_LOG_SIZE 6	  

	typedef struct
	{
		uint32_t block_next;	  
		uint32_t block_start;	  
		uint32_t log_num_total;	  
		uint32_t log_num_per_blk; 
		uint8_t Err;			  
		uint8_t Checked;		  
		uint16_t save_cnt;		  
	} block_log_info_type;

	typedef struct
	{
		uint16_t (*init)(void);
		uint16_t (*save)(void);
		void (*read)(int32_t site, uint8_t *dat);
		void (*clr)(void);
		int32_t (*time_search)(uint32_t time, int8_t mode);
		int32_t (*site_move)(int32_t site, int32_t inc);
		int32_t (*get_next_site)(void);

		int32_t (*site_iter)(
			int32_t s_start, int32_t s_end,
			int32_t (*iter_back)(int32_t site, uint8_t *dat));

		int32_t (*time_iter)(
			uint32_t tim_start, uint32_t tim_end,
			int32_t (*iter_back)(int32_t site, uint8_t *dat));

		uint16_t (*buf_init)(void);
		uint16_t (*buf_save)(void *dat);
		uint16_t (*buf_read)(uint32_t site, void *buff);
		uint32_t (*buf_site2addr)(uint32_t site);
		int32_t (*buf_time_search)(uint32_t time, int8_t mode);
		uint16_t (*buf_modify)(uint32_t site, void *dat, uint16_t offset, uint16_t len);
	} block_log_api_type;

	typedef struct
	{
		uint32_t block_base;									  
		uint16_t block_amount;									  
		block_log_info_type *Info;								  
		const log_buff_cfg_type buf_cfg;						  
		void (*Erase)(uint32_t block_addr);						  
		void (*Program)(uint32_t block_addr);					  
		void (*Read)(uint32_t Addr, uint16_t Len, uint8_t *Data); 
		const block_log_api_type *api;
	} block_log_cfg_type;

	uint16_t log_buff_init(const block_log_cfg_type *cfg); 
	uint16_t log_buff_save(const block_log_cfg_type *cfg, void *dat);
	uint16_t log_buff_read(const block_log_cfg_type *cfg, uint32_t site, void *buff);
	int32_t log_buff_time_search(const block_log_cfg_type *cfg, uint32_t time, int8_t mode);						  
	uint32_t log_buff_site2addr(const block_log_cfg_type *cfg, uint32_t site);										  
	uint16_t log_buff_modify(const block_log_cfg_type *cfg, uint32_t site, void *dat, uint16_t offset, uint16_t len); 

	uint16_t block_log_check(const block_log_cfg_type *Cfg);
	uint16_t block_log_save(const block_log_cfg_type *Cfg);
	void block_log_read(const block_log_cfg_type *cfg, int32_t site, uint8_t *dat);
	void block_log_clr(const block_log_cfg_type *cfg);

	int32_t block_log_time_search(const block_log_cfg_type *Cfg, uint32_t time, int8_t mode);

	int32_t block_log_site_amount(const block_log_cfg_type *cfg, int32_t site_start, int32_t site_end);

	int8_t block_log_site_check(const block_log_cfg_type *cfg, int32_t site);
	int32_t block_log_site_move(const block_log_cfg_type *cfg, int32_t site, int32_t inc);
	int32_t block_log_get_next_site(const block_log_cfg_type *cfg);

	int32_t block_log_site_iter(
		const block_log_cfg_type *cfg, int32_t s_start, int32_t s_end,
		int32_t (*iter_back)(int32_t site, uint8_t *dat));

	int32_t block_log_time_iter(
		const block_log_cfg_type *cfg, uint32_t tim_start, uint32_t tim_end,
		int32_t (*iter_back)(int32_t site, uint8_t *dat));

#define block_log_api_make(obj)                                                                \
                                                                                               \
	static uint16_t obj##_init(void);                                                          \
	static uint16_t obj##_save(void);                                                          \
	static void obj##_read(int32_t site, uint8_t *dat);                                        \
	static void obj##_clr(void);                                                               \
	static int32_t obj##_time_search(uint32_t time, int8_t mode);                              \
	static int32_t obj##_site_move(int32_t site, int32_t inc);                                 \
	static int32_t obj##_get_next_site(void);                                                  \
	static int32_t obj##_site_iter(                                                            \
		int32_t s_start, int32_t s_end,                                                        \
		int32_t (*iter_back)(int32_t site, uint8_t * dat));                                    \
	static int32_t obj##_time_iter(                                                            \
		uint32_t tim_start, uint32_t tim_end,                                                  \
		int32_t (*iter_back)(int32_t site, uint8_t * dat));                                    \
                                                                                               \
	static uint16_t obj##_buf_init(void);                                                      \
	static uint16_t obj##_buf_save(void *dat);                                                 \
	static uint16_t obj##_buf_read(uint32_t site, void *buff);                                 \
	static uint32_t obj##_buf_site2addr(uint32_t site);                                        \
	static int32_t obj##_buf_time_search(uint32_t time, int8_t mode);                          \
	static uint16_t obj##_buf_modify(uint32_t site, void *dat, uint16_t offset, uint16_t len); \
                                                                                               \
	uint16_t obj##_init(void)                                                                  \
	{                                                                                          \
		return block_log_check(&obj);                                                          \
	}                                                                                          \
	uint16_t obj##_save(void)                                                                  \
	{                                                                                          \
		return block_log_save(&obj);                                                           \
	}                                                                                          \
	void obj##_read(int32_t site, uint8_t *dat)                                                \
	{                                                                                          \
		block_log_read(&obj, site, dat);                                                       \
	}                                                                                          \
	void obj##_clr(void)                                                                       \
	{                                                                                          \
		block_log_clr(&obj);                                                                   \
	}                                                                                          \
	int32_t obj##_time_search(uint32_t time, int8_t mode)                                      \
	{                                                                                          \
		return block_log_time_search(&obj, time, mode);                                        \
	}                                                                                          \
	int32_t obj##_site_move(int32_t site, int32_t inc)                                         \
	{                                                                                          \
		return block_log_site_move(&obj, site, inc);                                           \
	}                                                                                          \
	static int32_t obj##_get_next_site(void)                                                   \
	{                                                                                          \
		return block_log_get_next_site(&obj);                                                  \
	}                                                                                          \
	static int32_t obj##_site_iter(                                                            \
		int32_t s_start, int32_t s_end,                                                        \
		int32_t (*iter_back)(int32_t site, uint8_t * dat))                                     \
	{                                                                                          \
		return block_log_site_iter(&obj, s_start, s_end, iter_back);                           \
	}                                                                                          \
	static int32_t obj##_time_iter(                                                            \
		uint32_t tim_start, uint32_t tim_end,                                                  \
		int32_t (*iter_back)(int32_t site, uint8_t * dat))                                     \
	{                                                                                          \
		return block_log_time_iter(&obj, tim_start, tim_end, iter_back);                       \
	}                                                                                          \
	uint16_t obj##_buf_init(void)                                                              \
	{                                                                                          \
		return log_buff_init(&obj);                                                            \
	}                                                                                          \
	uint16_t obj##_buf_save(void *dat)                                                         \
	{                                                                                          \
		return log_buff_save(&obj, dat);                                                       \
	}                                                                                          \
	uint16_t obj##_buf_read(uint32_t site, void *buff)                                         \
	{                                                                                          \
		return log_buff_read(&obj, site, buff);                                                \
	}                                                                                          \
	uint32_t obj##_buf_site2addr(uint32_t site)                                                \
	{                                                                                          \
		return log_buff_site2addr(&obj, site);                                                 \
	}                                                                                          \
	int32_t obj##_buf_time_search(uint32_t time, int8_t mode)                                  \
	{                                                                                          \
		return log_buff_time_search(&obj, time, mode);                                         \
	}                                                                                          \
	static uint16_t obj##_buf_modify(uint32_t site, void *dat, uint16_t offset, uint16_t len)  \
	{                                                                                          \
		return log_buff_modify(&obj, site, dat, offset, len);                                  \
	}                                                                                          \
	const block_log_api_type obj##_api = {                                                     \
		obj##_init,                                                                            \
		obj##_save,                                                                            \
		obj##_read,                                                                            \
		obj##_clr,                                                                             \
		obj##_time_search,                                                                     \
		obj##_site_move,                                                                       \
		obj##_get_next_site,                                                                   \
		obj##_site_iter,                                                                       \
		obj##_time_iter,                                                                       \
		obj##_buf_init,                                                                        \
		obj##_buf_save,                                                                        \
		obj##_buf_read,                                                                        \
		obj##_buf_site2addr,                                                                   \
		obj##_buf_time_search,                                                                 \
		obj##_buf_modify}

#define block_log_api_ref(obj) extern const block_log_api_type obj##_api
#define block_log_api_name(obj) &obj##_api

#ifdef __cplusplus
}
#endif

#endif
